home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / oleo130s.zip / OLEO130S.TAR / oleo-1.3 / utils.c < prev    next >
C/C++ Source or Header  |  1993-03-26  |  20KB  |  1,189 lines

  1. /*    Copyright (C) 1990, 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <stdio.h>
  20. #include <errno.h>
  21. #include "sysdef.h"
  22.  
  23.  
  24. /* unistd.h defines _POSIX_VERSION on POSIX.1 systems.  */
  25. #if defined(DIRENT) || defined(_POSIX_VERSION)
  26. #include <dirent.h>
  27. #define NLENGTH(dirent) (strlen((dirent)->d_name))
  28. #else /* not (DIRENT or _POSIX_VERSION) */
  29. #define dirent direct
  30. #define NLENGTH(dirent) ((dirent)->d_namlen)
  31. #ifdef SYSNDIR
  32. #include <sys/ndir.h>
  33. #endif /* SYSNDIR */
  34. #ifdef SYSDIR
  35. #include <sys/dir.h>
  36. #endif /* SYSDIR */
  37. #ifdef NDIR
  38. #include <ndir.h>
  39. #endif /* NDIR */
  40. #endif /* not (DIRENT or _POSIX_VERSION) */
  41.  
  42. #ifdef __STDC__
  43. #define CONST const
  44. #undef NULL
  45. #else
  46. #define CONST
  47. #endif
  48.  
  49. #include <ctype.h>
  50. #include "utils.h"
  51.  
  52. #ifndef F_OK
  53. #define F_OK 0
  54. #endif
  55. #ifndef _IOSTRG
  56. #define _IOSTRG 0
  57. #endif
  58.  
  59. #ifdef __STDC__
  60. extern void abort (void);
  61. extern void *malloc (size_t);
  62. extern void *calloc (size_t, size_t);
  63. extern void *realloc (void *, size_t);
  64. #else
  65. extern void abort ();
  66. extern void *malloc ();
  67. extern void *calloc ();
  68. extern void *realloc ();
  69. #endif
  70.  
  71. extern int sys_nerr;
  72. extern char *sys_errlist[];
  73.  
  74. struct id
  75.   {
  76.     int flag;
  77.     FILE *fp;
  78.     char *name;
  79.   };
  80.  
  81. struct id *__id_s;
  82. int __id_n;
  83. int __id_f;
  84.  
  85. int __make_backups;
  86. int __backup_by_copying;
  87.  
  88. /* Stash argv[0] here so panic will know what the program is called */
  89. char *argv_name = 0;
  90.  
  91. /* Blow chunks! */
  92. #ifdef __STDC__
  93. void
  94. panic (const char *s,...)
  95. #else
  96. void
  97. panic (s, va_alist)
  98.      char *s;
  99.      va_dcl
  100. #endif
  101. {
  102.   va_list iggy;
  103.  
  104.   var_start (iggy, s);
  105.   if (argv_name)
  106.     fprintf (stderr, "%s:", argv_name);
  107.   vfprintf (stderr, s, iggy);
  108.   putc ('\n', stderr);
  109.   va_end (iggy);
  110.   exit (2);
  111. }
  112.  
  113. /* Given a file name, come up with a backup file name. . . */
  114. #ifdef __STDC__
  115. char *
  116. backup_file_name (char *file_name)
  117. #else
  118. char *
  119. backup_file_name (file_name)
  120.      char *file_name;
  121. #endif
  122. {
  123.   char *dir_name, *dir_end;
  124.  
  125.   DIR *dir;
  126.   register struct dirent *dp;
  127.   int len;
  128.   int max_fnum;
  129.   int cur_fnum;
  130.  
  131.   char *tmp_ptr;
  132.  
  133.   char *return_value;
  134.  
  135.   dir_end = (char *)rindex (file_name, '/');
  136.   if (dir_end)
  137.     {
  138.       dir_name = file_name;
  139.       file_name = dir_end + 1;
  140.       *dir_end = '\0';
  141.     }
  142.   else
  143.     {
  144.       dir_name = ".";
  145.     }
  146.   len = strlen (file_name);
  147.  
  148.   dir = opendir (dir_name);
  149.   if (dir == 0)
  150.     {
  151.       if (dir_end)
  152.     *dir_end = '/';
  153.       return (char *) 0;
  154.     }
  155.  
  156.   max_fnum = 0;
  157.   while (dp = readdir (dir))
  158.     {
  159.       if (!dp->d_ino
  160.       || NLENGTH (dp) <= len
  161.       || strncmp (dp->d_name, file_name, len)
  162.       || dp->d_name[len] != '.'
  163.       || dp->d_name[len + 1] != '~'
  164.       || dp->d_name[NLENGTH(dp) - 1] != '~')
  165.     continue;
  166.  
  167.       tmp_ptr = &(dp->d_name[len + 2]);
  168.       for (cur_fnum = 0; isdigit (*tmp_ptr); tmp_ptr++)
  169.     cur_fnum = cur_fnum * 10 + *tmp_ptr - '0';
  170.       if (tmp_ptr != &(dp->d_name[NLENGTH(dp) - 1]) || cur_fnum < max_fnum)
  171.     continue;
  172.       max_fnum = cur_fnum;
  173.     }
  174.   closedir (dir);
  175.   max_fnum++;
  176.   return_value = (char *) malloc (strlen (dir_name) + len + 12);
  177.   if (!return_value)
  178.     return (char *) 0;
  179.   sprintf (return_value, "%s/%s.~%d~", dir_name, file_name, max_fnum);
  180.   if (dir_end)
  181.     *dir_end = '/';
  182.   return return_value;
  183. }
  184.  
  185.  
  186. char *
  187. __fp_name (fp)
  188.      FILE *fp;
  189. {
  190.   int n;
  191.  
  192.   for (n = 0; n < __id_n; n++)
  193.     {
  194.       if (__id_s[n].fp == fp)
  195.     return __id_s[n].name;
  196.     }
  197.   return "{Unknown file pointer}";
  198. }
  199.  
  200. void
  201. __set_fp (fp, name, flag)
  202.      FILE *fp;
  203.      CONST char *name;
  204.      int flag;
  205. {
  206.   if (__id_s == 0)
  207.     {
  208.       __id_s = ck_malloc (20 * sizeof (struct id));
  209.       __id_n = 0;
  210.       __id_f = 20;
  211.     }
  212.   else
  213.     {
  214.       int n;
  215.  
  216.       for (n = 0; n < __id_n; n++)
  217.     if (__id_s[n].fp == fp)
  218.       {
  219.         free (__id_s[n].name);
  220.         __id_s[n] = __id_s[--__id_n];
  221.         __id_f++;
  222.         break;
  223.       }
  224.     }
  225.   if (__id_f == 0)
  226.     {
  227.       __id_f = 20;
  228.       __id_s = ck_realloc (__id_s, (__id_f + __id_n) * sizeof (struct id));
  229.     }
  230.   __id_s[__id_n].flag = flag;
  231.   __id_s[__id_n].name = strdup (name);
  232.   __id_s[__id_n].fp = fp;
  233.   __id_n++;
  234.   __id_f--;
  235. }
  236.  
  237. /* Open a file or a pipe */
  238. FILE *
  239. xopen (name, mode)
  240.      CONST char *name;
  241.      CONST char *mode;
  242. {
  243.   int flag = 0;
  244.   FILE *ret;
  245.  
  246.   while (*name == ' ')
  247.     name++;
  248.   if (*name == '!')
  249.     {
  250.       name++;
  251.       ret = popen (name, mode);
  252.       flag = 1;
  253.     }
  254.   else
  255.     ret = fopen (name, mode);
  256.   if (ret == 0)
  257.     return ret;
  258.   __set_fp (ret, name, flag);
  259.   return ret;
  260. }
  261.  
  262. /* Open a file, creating a backup file if needed. . . */
  263. FILE *
  264. fopen_with_backup (name, mode)
  265.      char *name;
  266.      CONST char *mode;
  267. {
  268.   char *newname;
  269.   struct stat stat_buf;
  270.   int old_file = 0;
  271.  
  272.   old_file = (stat (name, &stat_buf) >= 0);
  273.  
  274.   if (__make_backups && *mode == 'w' && access (name, F_OK) == 0)
  275.     {
  276.       newname = backup_file_name (name);
  277.       if (!newname)
  278.     return (FILE *) 0;
  279.       if (__backup_by_copying)
  280.     {
  281.       FILE *c_in, *c_out;
  282.       int n_read;
  283.       char buf[4096];
  284.       c_in = fopen (name, "r");
  285.       if (!c_in)
  286.         return 0;
  287.       c_out = fopen (newname, "w");
  288.       {
  289.         int fd;
  290.         if (!old_file || (stat (name, &stat_buf) < 0))
  291.           {
  292.         fclose (c_in);
  293.         return 0;
  294.           }
  295.         fd = creat (newname, stat_buf.st_mode);
  296.         if (fd < 0)
  297.           {
  298.         fclose (c_in);
  299.         return 0;
  300.           }
  301.         fchmod (fd, stat_buf.st_mode);
  302.         c_out = fdopen (fd, "w");
  303.         if (!c_out)
  304.           {
  305.         fclose (c_in);
  306.         close (fd);
  307.         return 0;
  308.           }
  309.       }
  310.       while ((n_read = fread (buf, 1, sizeof (buf), c_in)) > 0)
  311.         if (fwrite (buf, 1, n_read, c_out) != n_read)
  312.           {
  313.         fclose (c_in);
  314.         fclose (c_out);
  315.         return (FILE *) 0;
  316.           }
  317.       if (fclose (c_in) == EOF || fclose (c_out) == EOF)
  318.         return (FILE *) 0;
  319.     }
  320.       else
  321. #if defined(HAVE_RENAME)
  322.       if (rename (name, newname) < 0)
  323. #else
  324.       if (link (name, newname) || unlink (name))
  325. #endif
  326.     return (FILE *) 0;
  327.       free (newname);
  328.     }
  329.  
  330.   {
  331.     FILE * ret = fopen (name, mode);
  332.     if (ret && old_file)
  333.       fchmod (fileno (ret), stat_buf.st_mode);
  334.     return ret;
  335.   }
  336. }
  337.  
  338. /* Open a file or a pipe, creating a backup file if it's a file */
  339. FILE *
  340. xopen_with_backup (name, mode)
  341.      CONST char *name;
  342.      CONST char *mode;
  343. {
  344.   int flag;
  345.   FILE *ret;
  346.  
  347.   while (*name == ' ')
  348.     name++;
  349.   if (*name == '|')
  350.     {
  351.       ret = popen (name + 1, mode);
  352.       flag = 1;
  353.     }
  354.   else
  355.     {
  356.       ret = fopen_with_backup (name, mode);
  357.       flag = 0;
  358.     }
  359.   if (ret == 0)
  360.     return ret;
  361.   __set_fp (ret, name, flag);
  362.   return ret;
  363. }
  364.  
  365. /* Close something opened with xopen. . . */
  366. int
  367. xclose (fp)
  368.      FILE *fp;
  369. {
  370.   int ret;
  371.   int n;
  372.  
  373.   for (n = 0; n < __id_n; n++)
  374.     {
  375.       if (__id_s[n].fp == fp)
  376.     break;
  377.     }
  378.   if (n == __id_n)
  379.     panic ("Unknown file pointer %p given to xclose", fp);
  380.   if (__id_s[n].flag)
  381.     ret = pclose (fp);
  382.   else
  383.     ret = fclose (fp);
  384.   return ret;
  385. }
  386.  
  387. /* Fclose or panic */
  388. void
  389. ck_fclose (stream)
  390.      FILE *stream;
  391. {
  392.   if (fclose (stream) == EOF)
  393.     panic ("Couldn't close %s", __fp_name (stream));
  394. }
  395.  
  396. /* fopen or panic */
  397. void *
  398. ck_malloc (size)
  399.      size_t size;
  400. {
  401.   void *ret;
  402.  
  403.   ret = malloc (size);
  404.   if (ret == (void *) 0)
  405.     panic ("Couldn't allocate %u bytes", size);
  406.   return ret;
  407. }
  408.  
  409. #ifdef __STDC__
  410. char *
  411. ck_savestr (char *str)
  412. #else
  413. char *
  414. ck_savestr (str)
  415.      char *str;
  416. #endif
  417. {
  418.   char *newstr = 0;
  419.   if (str)
  420.     {
  421.       int len = strlen (str) + 1;
  422.       newstr = (char *) ck_malloc (len);
  423.       bcopy (str, newstr, len);
  424.     }
  425.   return newstr;
  426. }
  427.  
  428.  
  429. #ifdef __STDC__
  430. char *
  431. ck_savestrn (char *str, int n)
  432. #else
  433. char *
  434. ck_savestrn (str, n)
  435.      char *str;
  436.      int n;
  437. #endif
  438. {
  439.   char *newstr = 0;
  440.   if (str)
  441.     {
  442.       newstr = (char *) ck_malloc (n + 1);
  443.       bcopy (str, newstr, n);
  444.       newstr[n] = '\0';
  445.     }
  446.   return newstr;
  447. }
  448.  
  449. #ifdef __STDC__
  450. void *
  451. ck_calloc (size_t size)
  452. #else
  453. void *
  454. ck_calloc (size)
  455.      size_t size;
  456. #endif
  457. {
  458.   void *ret;
  459.  
  460.   ret = calloc (size, 1);
  461.   if (ret == (void *) 0)
  462.     panic ("Couldn't allocate %u bytes", size);
  463.   return ret;
  464. }
  465.  
  466. /* Realloc or panic */
  467. #ifdef __STDC__
  468. void *
  469. ck_realloc (void *ptr, size_t size)
  470. #else
  471. void *
  472. ck_realloc (ptr, size)
  473.      void *ptr;
  474.      size_t size;
  475. #endif
  476. {
  477.   void *ret;
  478.  
  479.   if (!ptr)
  480.     ret = malloc (size);
  481.   else
  482.     ret = realloc (ptr, size);
  483.   if (ret == (void *) 0)
  484.     panic ("Couldn't re-allocate %u bytes from %p", size, ptr);
  485.   return ret;
  486. }
  487.  
  488. /* Do a sprintf into an allocated buffer. */
  489. char *
  490. #ifdef __STDC__
  491. mk_sprintf (char *str,...)
  492. {
  493.   va_list iggy;
  494. #ifdef __TURBOC__
  495.   static
  496. #endif
  497.   char tmpbuf[1024 * 8];
  498.   char *ret;
  499.  
  500.   va_start (iggy, str);
  501.   vsprintf (tmpbuf, str, iggy);
  502.   va_end (iggy);
  503.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  504.   strcpy (ret, tmpbuf);
  505.   return ret;
  506. }
  507.  
  508. #else
  509.  
  510. mk_sprintf (str, va_alist)
  511.      char *str;
  512.      va_dcl
  513. {
  514.   va_list iggy;
  515. #ifdef __TURBOC__
  516.   static
  517. #endif
  518.   char tmpbuf[1024 * 8];
  519.   char *ret;
  520.  
  521.   va_start (iggy);
  522.   vsprintf (tmpbuf, str, iggy);
  523.   va_end (iggy);
  524.  
  525.   ret = (char *) ck_malloc (strlen (tmpbuf) + 1);
  526.   strcpy (ret, tmpbuf);
  527.   return ret;
  528. }
  529.  
  530. #endif
  531.  
  532. /* Implement a variable sized LIFO stack of pointers to void */
  533.  
  534. struct stack
  535.   {
  536.     int allocated;
  537.     int used;
  538.     void **buf;
  539.   };
  540.  
  541. #define MIN_STACK 20
  542.  
  543. void *
  544. init_stack ()
  545. {
  546.   struct stack *b;
  547.  
  548.   b = (struct stack *) ck_malloc (sizeof (struct stack));
  549.   b->allocated = MIN_STACK;
  550.   b->used = 0;
  551.   b->buf = (void **) ck_malloc (MIN_STACK * sizeof (void *));
  552.   return (void *) b;
  553. }
  554.  
  555. void
  556. flush_stack (bb)
  557.      void *bb;
  558. {
  559.   struct stack *b;
  560.  
  561.   b = (struct stack *) bb;
  562.   free (b->buf);
  563.   b->buf = 0;
  564.   b->allocated = 0;
  565.   b->used = 0;
  566.   free (b);
  567. }
  568.  
  569. void
  570. push_stack (bb, add)
  571.      void *bb;
  572.      void *add;
  573. {
  574.   struct stack *b;
  575.  
  576.   b = (struct stack *) bb;
  577.   if (b->allocated == b->used)
  578.     {
  579.       b->allocated *= 2;
  580.       b->buf = (void **) ck_realloc (b->buf, b->allocated * sizeof (void *));
  581.     }
  582.   b->buf[(b->used)++] = add;
  583. }
  584.  
  585. void *
  586. pop_stack (bb)
  587.      void *bb;
  588. {
  589.   struct stack *b;
  590.  
  591.   b = (struct stack *) bb;
  592.   if (b->used == 0)
  593.     return (void *) 0;
  594.   return b->buf[--(b->used)];
  595. }
  596.  
  597. int
  598. size_stack (bb)
  599.      void *bb;
  600. {
  601.   struct stack *b;
  602.  
  603.   b = (struct stack *) bb;
  604.   return b->used;
  605. }
  606.  
  607. #ifndef HAVE_STRDUP
  608. char *
  609. strdup (str)
  610.      CONST char *str;
  611. {
  612.   char *ret;
  613.  
  614.   ret = (char *) ck_malloc (strlen (str) + 2);
  615.   strcpy (ret, str);
  616.   return ret;
  617. }
  618. #endif
  619.  
  620. #ifndef HAVE_STRICMP
  621. /*
  622.  * stricmp - compare string s1 to s2, ignoring case
  623.  */
  624.  
  625. #ifdef __STDC__
  626. int
  627. stricmp (const char * s1, const char * s2)
  628. #else
  629. int
  630. stricmp (s1, s2)
  631.      CONST char *s1;
  632.      CONST char *s2;
  633. #endif
  634. {
  635.   register CONST char *scan1;
  636.   register CONST char *scan2;
  637.   register char chr1, chr2;
  638.  
  639.   scan1 = s1;
  640.   scan2 = s2;
  641.   do
  642.     {
  643.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  644.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  645.       scan1++;
  646.       scan2++;
  647.     }
  648.   while (chr1 && chr1 == chr2);
  649.  
  650.   /*
  651.      * The following case analysis is necessary so that characters
  652.      * which look negative collate low against normal characters but
  653.      * high against the end-of-string NUL.
  654.      */
  655.   if (chr1 == '\0' && chr2 == '\0')
  656.     return 0;
  657.   else if (chr1 == '\0')
  658.     return -1;
  659.   else if (chr2 == '\0')
  660.     return 1;
  661.   else
  662.     return chr1 - chr2;
  663. }
  664. #endif
  665.  
  666. #ifndef HAVE_STRINCMP
  667. /* strincmp - compare first N chars of strings S1 and S2 */
  668. #ifdef __STDC__
  669. int
  670. strincmp (const char * s1, const char * s2, size_t n)
  671. #else
  672. int
  673. strincmp (s1, s2, n)
  674.      CONST char *s1;
  675.      CONST char *s2;
  676.      size_t n;
  677. #endif
  678. {
  679.   register CONST char *scan1;
  680.   register CONST char *scan2;
  681.   register size_t count;
  682.   register char chr1, chr2;
  683.  
  684.   scan1 = s1;
  685.   scan2 = s2;
  686.   count = n;
  687.   do
  688.     {
  689.       chr1 = isupper (*scan1) ? tolower (*scan1) : *scan1;
  690.       chr2 = isupper (*scan2) ? tolower (*scan2) : *scan2;
  691.       scan1++;
  692.       scan2++;
  693.     }
  694.   while (--count != 0 && chr1 && chr1 == chr2);
  695.  
  696.   /* if (count == (size_t)-1)
  697.         return 0; */
  698.  
  699.   /*
  700.      * The following case analysis is necessary so that characters
  701.      * which look negative collate low against normal characters but
  702.      * high against the end-of-string NUL.
  703.      */
  704.   if (chr1 == '\0' && chr2 == '\0')
  705.     return 0;
  706.   else if (chr1 == '\0')
  707.     return -1;
  708.   else if (chr2 == '\0')
  709.     return 1;
  710.   else
  711.     return chr1 - chr2;
  712. }
  713. #endif
  714.  
  715. #ifndef HAVE_STRSTR
  716. CONST char *
  717. strstr (s, wanted)
  718.      CONST char *s;
  719.      CONST char *wanted;
  720. {
  721.   register CONST char *scan;
  722.   register size_t len;
  723.   register char firstc;
  724.  
  725.   /*
  726.      * The odd placement of the two tests is so "" is findable.
  727.      * Also, we inline the first char for speed.
  728.      * The ++ on scan has been moved down for optimization.
  729.      */
  730.   firstc = *wanted;
  731.   len = strlen (wanted);
  732.   for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
  733.     if (*scan++ == '\0')
  734.       return (char *) 0;
  735.   return scan;
  736. }
  737. #endif
  738.  
  739. #ifdef __STDC__
  740. char *
  741. err_msg (void)
  742. #else
  743. char *
  744. err_msg ()
  745. #endif
  746. {
  747.   int n;
  748.   static char buf[80];
  749.  
  750.   n = errno;
  751.  
  752.   if (n < sys_nerr)
  753.     return sys_errlist[n];
  754.   sprintf (buf, "Unknown error code %d (%#x)", n, n);
  755.   return buf;
  756. }
  757.  
  758.  
  759. /* Take a quoted string and return the character it represents */
  760. #ifdef __STDC__
  761. int
  762. string_to_char (char ** ptr)
  763. #else
  764. int
  765. string_to_char (ptr)
  766.      char **ptr;
  767. #endif
  768. {
  769.   char *str;
  770.   int i;
  771.   char c1, c2;
  772.  
  773.   str = *ptr;
  774.   if (str[0] == '\\')
  775.     {
  776.       switch (str[1])
  777.     {
  778.     case ' ':
  779.       i = ' ';
  780.       break;
  781.     case '\\':
  782.       i = '\\';
  783.       break;
  784.     case 'b':
  785.       i = '\b';
  786.       break;
  787.     case 'f':
  788.       i = '\f';
  789.       break;
  790.     case 'n':
  791.       i = '\n';
  792.       break;
  793.     case 'r':
  794.       i = '\r';
  795.       break;
  796.     case 't':
  797.       i = '\t';
  798.       break;
  799.     case 'x':
  800.       c1 = str[2];
  801.       c2 = str[3];
  802.       if (isxdigit (c1))
  803.         {
  804.           if (isdigit (c1))
  805.         c1 -= '0';
  806.           else if (isupper (c1))
  807.         c1 -= 'A';
  808.           else
  809.         c1 -= 'a';
  810.           if (isxdigit (c2))
  811.         {
  812.           if (isdigit (c2))
  813.             c2 -= '0';
  814.           else if (isupper (c2))
  815.             c2 -= 'A';
  816.           else
  817.             c2 -= 'a';
  818.           i = c1 * 0x10 + c2;
  819.           str++;
  820.         }
  821.           else
  822.         i = c1;
  823.         }
  824.       else
  825.         i = 'x';
  826.       break;
  827.  
  828.     case '0':
  829.     case '1':
  830.     case '2':
  831.     case '3':
  832.     case '4':
  833.     case '5':
  834.     case '6':
  835.     case '7':
  836.       if (str[2] >= '0' && str[2] <= '7')
  837.         {
  838.           if (str[3] >= '0' && str[3] <= '7')
  839.         {
  840.           i = (str[1] - '0') * 0100 + (str[2] - '0') * 010 + (str[3] - '0');
  841.           str += 2;
  842.         }
  843.           else
  844.         {
  845.           i = (str[1] - '0') * 010 + (str[2] - '0');
  846.           str++;
  847.         }
  848.         }
  849.       else
  850.         i = str[1] - '0';
  851.       break;
  852.     default:
  853.       i = str[0];
  854.       --str;
  855.       break;
  856.     }
  857.       str += 2;
  858.       *ptr = str;
  859.       return i;
  860.     }
  861.  
  862.   if (str[0] == 'M' && str[1] == '-')
  863.     {
  864.       i = 0x80;
  865.       str += 2;
  866.     }
  867.   else
  868.     i = 0;
  869.  
  870.   if (str[0] == '^')
  871.     {
  872.       if (str[1] == '?')
  873.     i += 0x7f;
  874.       else if (str[1] >= '@' && str[1] <= '_')
  875.     i |= str[1] - '@';
  876.       else if (str[1] >= 'a' && str[1] <= 'z')
  877.     i = str[1] - 'a' + 1;
  878.       else if (str[1] == '\0' || isspace (str[1]))
  879.     i = '^';
  880.       else
  881.     return -1;
  882.       str += 2;
  883.     }
  884.   else
  885.     {
  886.       i |= str[0];
  887.       str++;
  888.     }
  889.   *ptr = str;
  890.   return i;
  891. }
  892.  
  893. /* Take a char and turn it into a readable string */
  894. #ifdef __STDC__
  895. char *
  896. char_to_string (int ch)
  897. #else
  898. char *
  899. char_to_string (ch)
  900.      int ch;
  901. #endif
  902. {
  903.   static char buf[5] = "M-";
  904.  
  905.   if (ch >= ' ' && ch <= '~')
  906.     {
  907.       buf[3] = ch;
  908.       return &buf[3];
  909.     }
  910.   if (ch & 0x80)
  911.     {
  912.       ch &= 0x7f;
  913.       if (ch == 0x7f || ch < ' ')
  914.     {
  915.       buf[2] = '^';
  916.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  917.     }
  918.       else
  919.     {
  920.       buf[2] = ch;
  921.       buf[3] = '\0';
  922.     }
  923.       return &buf[0];
  924.     }
  925.   if (ch == 0x7f || ch < ' ')
  926.     {
  927.       buf[2] = '^';
  928.       buf[3] = (ch == 0x7f ? '?' : ch + '@');
  929.       return &buf[2];
  930.     }
  931.   return "huh";
  932. }
  933.  
  934.  
  935. #ifdef __STDC__
  936. long
  937. astol (char **ptr)
  938. #else
  939. long
  940. astol (ptr)
  941.      char **ptr;
  942. #endif
  943. {
  944.   register long i = 0;
  945.   register int c;
  946.   int sign = 1;
  947.   char *s;
  948.  
  949.   s = *ptr;
  950.   /* Skip whitespace */
  951.   while (isspace (*s))
  952.     if (*s++ == '\0')
  953.       {
  954.     *ptr = s;
  955.     return (0);
  956.       }
  957.   /* Check for - or + */
  958.   if (*s == '-')
  959.     {
  960.       s++;
  961.       sign = -1;
  962.     }
  963.   else if (*s == '+')
  964.     s++;
  965.  
  966.   /* Read in the digits */
  967.   for (; c = *s; s++)
  968.     {
  969.       if (!isdigit (c) || i > 214748364 || (i == 214748364 && c > (sign > 0 ? '7' : '8')))
  970.     break;
  971.       i = i * 10 + c - '0';
  972.     }
  973.   *ptr = s;
  974.   return i * sign;
  975. }
  976.  
  977. /*
  978.  *    astof - accept a number of the form:
  979.  *        (and ignores leading white space)
  980.  *
  981.  *    null    ::=
  982.  *    digit    ::= 0|1|2|3|4|5|6|7|8|9
  983.  *    digits    ::= <digit>*
  984.  *    DIGITS    ::= <digit>+
  985.  *    sign    ::= <null> | + | -
  986.  *    -------------------------------
  987.  *        accepted:
  988.  *    -------------------------------
  989.  *    integer    ::= <sign><DIGITS>
  990.  *    real    ::= <integer> . <digits> | <null> . <DIGITS>
  991.  *    epart    ::= e <integer> | E <integer>
  992.  *    float    ::= <integer> <epart> | <real> <epart>
  993.  *
  994.  *    Always returned as a double
  995.  *
  996.  *    There is no particular attempt to reduce mpys/divs
  997.  *    those machines that are still out there (eg. PDP11/Small)
  998.  *    that shun floating point arithmetic might rethink this routine.
  999.  */
  1000.  
  1001. static double exps0[10] =
  1002. {1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
  1003. static double exps1[10] =
  1004. {1E00, 1E10, 1E20, 1E30
  1005. #ifndef vax
  1006.  ,1E40, 1E50, 1E60, 1E70, 1E80, 1E90
  1007. #endif
  1008. };
  1009.  
  1010. #define REGISTER register
  1011.  
  1012. #ifdef __STDC__
  1013. double
  1014. astof (char **sp)
  1015. #else
  1016. double
  1017. astof (sp)
  1018.      char **sp;
  1019. #endif
  1020. {
  1021.   REGISTER char *s;
  1022.   REGISTER char *cp;
  1023.   long ipart, epart;
  1024.   int neg = 0;
  1025.   double res;
  1026.   int n;
  1027.  
  1028.   s = *sp;
  1029.   while (isspace (*s))
  1030.     {
  1031.       s++;
  1032.       if (*s == '\0')
  1033.     {
  1034.       *sp = s;
  1035.       return (0.0);
  1036.     }
  1037.     }
  1038.   /*
  1039.      *    Need to handle sign here due to '-.3' or '-0.3'
  1040.      */
  1041.   if (*s == '-')
  1042.     {
  1043.       ++neg;
  1044.       ++s;
  1045.     }
  1046.   else if (*s == '+')
  1047.     ++s;
  1048.   cp = s;
  1049.   /*
  1050.      *    get ipart handling '.n' case
  1051.      */
  1052.   res = 0.0;
  1053.   while (isdigit (*s))
  1054.     {
  1055.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1056.     ipart = ipart * 10 + *s++ - '0';
  1057.       res = res * exps0[n] + (double) ipart;
  1058.     }
  1059.   if (s == cp)
  1060.     {
  1061.       if (*s == '.')
  1062.     ipart = 0;
  1063.       else
  1064.     {
  1065.       *sp = s;
  1066.       return (0.0);
  1067.     }
  1068.     }
  1069.   /*
  1070.      *    either we find a '.' or e|E or done
  1071.      */
  1072.   if (*s == '.')
  1073.     {
  1074.       int m;
  1075.       ++s;
  1076.  
  1077.       m = 0;
  1078.       while (isdigit (*s))
  1079.     {
  1080.       for (n = 0, ipart = 0; n < 6 && isdigit (*s); n++)
  1081.         ipart = ipart * 10 + *s++ - '0';
  1082.       m += n;
  1083.       if (m >= 100)
  1084.         continue;
  1085.       if (m >= 10)
  1086.         res += ((double) ipart) / (exps1[m / 10] * exps0[m % 10]);
  1087.       else
  1088.         res += ((double) ipart) / exps0[m];
  1089.     }
  1090.     }
  1091.   /*
  1092.      *    In either case (.) handle E part
  1093.      */
  1094.   if (*s == 'e' || *s == 'E')
  1095.     {
  1096.       int eneg;
  1097.  
  1098.       ++s;
  1099.       epart = 0;
  1100.       eneg = 0;
  1101.       if (*s == '-')
  1102.     {
  1103.       eneg++;
  1104.       s++;
  1105.     }
  1106.       else if (*s == '+')
  1107.     s++;
  1108.       while (isdigit (*s))
  1109.     epart = epart * 10 + *s++ - '0';
  1110.       if (eneg)
  1111.     {
  1112. #ifndef vax
  1113.       while (epart >= 100)
  1114.         {
  1115.           res /= 1E100;
  1116.           epart -= 100;
  1117.         }
  1118. #endif
  1119.       if (epart > 9)
  1120.         {
  1121.           res /= exps1[epart / 10];
  1122.           epart %= 10;
  1123.         }
  1124.       if (epart)
  1125.         res /= exps0[epart];
  1126.     }
  1127.       else
  1128.     {
  1129. #ifndef vax
  1130.       while (epart >= 100)
  1131.         {
  1132.           res *= 1E100;
  1133.           epart -= 100;
  1134.         }
  1135. #endif
  1136.       if (epart > 9)
  1137.         {
  1138.           res *= exps1[epart / 10];
  1139.           epart %= 10;
  1140.         }
  1141.       if (epart)
  1142.         res *= exps0[epart];
  1143.     }
  1144.     }
  1145.   /*
  1146.      *    fix sign
  1147.      */
  1148.   if (neg)
  1149.     res = -res;
  1150.   *sp = s;
  1151.   return (res);
  1152. }
  1153.  
  1154. #ifdef TEST_ASTOF
  1155. main ()
  1156. {
  1157.   char buf[80];
  1158.   char *ptr;
  1159.   double at, ast;
  1160.   double atof ();
  1161.  
  1162.   while (gets (buf))
  1163.     {
  1164.       at = atof (buf);
  1165.       ptr = buf;
  1166.       ast = astof (&ptr);
  1167.       printf ("%15.6f %15.6f %s ", at, ast, at == ast ? "eq" : "NEQ");
  1168.       if (*ptr)
  1169.     printf ("%s->'%s'\n", buf, ptr);
  1170.       else
  1171.     printf ("%s\n", buf);
  1172.     }
  1173. }
  1174. char *
  1175. ck_savestr (str)
  1176.      char *str;
  1177. {
  1178.   char *newstr = 0;
  1179.   if (str)
  1180.     {
  1181.       int len = strlen (str) + 1;
  1182.       newstr = (char *) ck_malloc (len);
  1183.       bcopy (str, newstr, len);
  1184.     }
  1185.   return newstr;
  1186. }
  1187.  
  1188. #endif
  1189.